package lol.clann.bukkit.pluginboot.util;

import lol.clann.clannboot.annotation.inject.Inject;
import lol.clann.clannboot.annotation.svc.Service;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.block.Block;
import org.bukkit.command.CommandException;
import org.bukkit.inventory.ItemStack;

import java.io.File;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

/**
 * @author pyz
 * @date 2018/8/11 上午11:09
 */
@Service(priority = Integer.MAX_VALUE)
public class Validator {

    @Inject
    private PlayerUtils playerUtils;
    @Inject
    private ItemStackUtils itemStackUtils;
    @Inject
    private BlockUtils blockUtils;
    @Inject
    private EntityUtils entityUtils;

    public void exist(File f) {
        exist(f, "文件不存在:" + f.getAbsolutePath());
    }

    public void exist(File f, String message) {
        if (!f.exists()) {
            throw new CommandException(message);
        }
    }

    public void notEmpty(Block block) {
        notEmpty(block, "无效的方块");
    }

    public void notEmpty(ItemStack itemStack) {
        notEmpty(itemStack, "无效的物品");
    }

    public void notEmpty(Block block, String message) {
        isTrue(!blockUtils.isEmpty(block), message);
    }

    public void notEmpty(ItemStack itemStack, String message) {
        isTrue(!itemStackUtils.isEmpty(itemStack), message);
    }

    public void isTrue(boolean b) {
        isTrue(b, "");
    }

    public void isTrue(boolean b, String message, Object... args) {
        if (b) {
            return;
        }
        throw new CommandException(String.format(message, args));
    }

    public void notNull(Object o, String message) {
        isTrue(o != null, message);
    }

    public void notNull(Object o) {
        isTrue(o != null);
    }

    public <T> void notEmpty(T[] array, String message) {
        if (array == null) {
            throw new CommandException(message);
        } else if (array.length == 0) {
            throw new CommandException(message);
        }
    }

    public <T> void notEmpty(T[] array) {
        if (array == null || array.length == 0) {
            throw new CommandException();
        }
    }

    public <T extends Collection<?>> void notEmpty(T collection, String message) {
        if (collection == null) {
            throw new CommandException(message);
        } else if (collection.isEmpty()) {
            throw new CommandException(message);
        }
    }

    public <T extends Collection<?>> void notEmpty(T collection) {
        notEmpty(collection, "");
    }

    public <T extends Map<?, ?>> void notEmpty(T map, String message, Object... values) {
        if (map == null) {
            throw new CommandException(message);
        } else if (map.isEmpty()) {
            throw new CommandException(message);
        }
    }

    public <T extends Map<?, ?>> void notEmpty(T map) {
        notEmpty(map, "");
    }

    public <T extends CharSequence> void notEmpty(T chars, String message, Object... values) {
        if (chars == null) {
            throw new CommandException(message);
        } else if (chars.length() == 0) {
            throw new CommandException(message);
        }
    }

    public <T extends CharSequence> void notEmpty(T chars) {
        notEmpty(chars, "");
    }

    public <T extends CharSequence> void notBlank(T chars, String message, Object... values) {
        if (chars == null) {
            throw new CommandException(message);
        } else if (StringUtils.isBlank(chars)) {
            throw new CommandException(message);
        }
    }

    public <T extends CharSequence> void notBlank(T chars) {
        notBlank(chars, "");
    }

    public <T> void noNullElements(T[] array, String message) {
        notNull(array);

        for (int i = 0; i < array.length; ++i) {
            if (array[i] == null) {
                throw new CommandException(i + " " + message);
            }
        }
    }

    public <T> void noNullElements(T[] array) {
        noNullElements(array, "");
    }

    public <T extends Iterable<?>> void noNullElements(T iterable, String message) {
        notNull(iterable);
        int i = 0;

        for (Iterator it = iterable.iterator(); it.hasNext(); ++i) {
            if (it.next() == null) {
                throw new CommandException(i + " " + message);
            }
        }
    }

    public <T extends Iterable<?>> void noNullElements(T iterable) {
        noNullElements(iterable, "");
    }

    public <T> void inclusiveBetween(T start, T end, Comparable<T> value) {
        if (value.compareTo(start) < 0 || value.compareTo(end) > 0) {
            throw new CommandException(String.format("The value %s is not in the specified inclusive range of %s to %s", value, start, end));
        }
    }

    public <T> void inclusiveBetween(T start, T end, Comparable<T> value, String message, Object... values) {
        if (value.compareTo(start) < 0 || value.compareTo(end) > 0) {
            throw new CommandException(message);
        }
    }

    public void inclusiveBetween(long start, long end, long value) {
        if (value < start || value > end) {
            throw new CommandException(String.format("The value %s is not in the specified inclusive range of %s to %s", value, start, end));
        }
    }

    public void inclusiveBetween(long start, long end, long value, String message) {
        if (value < start || value > end) {
            throw new CommandException(String.format(message));
        }
    }

    public void inclusiveBetween(double start, double end, double value) {
        if (value < start || value > end) {
            throw new CommandException(String.format("The value %s is not in the specified inclusive range of %s to %s", value, start, end));
        }
    }

    public void inclusiveBetween(double start, double end, double value, String message) {
        if (value < start || value > end) {
            throw new CommandException(String.format(message));
        }
    }

    public <T> void exclusiveBetween(T start, T end, Comparable<T> value) {
        if (value.compareTo(start) <= 0 || value.compareTo(end) >= 0) {
            throw new CommandException(String.format("The value %s is not in the specified exclusive range of %s to %s", value, start, end));
        }
    }

    public <T> void exclusiveBetween(T start, T end, Comparable<T> value, String message, Object... values) {
        if (value.compareTo(start) <= 0 || value.compareTo(end) >= 0) {
            throw new CommandException(message);
        }
    }

    public void exclusiveBetween(long start, long end, long value) {
        if (value <= start || value >= end) {
            throw new CommandException(String.format("The value %s is not in the specified exclusive range of %s to %s", value, start, end));
        }
    }

    public void exclusiveBetween(long start, long end, long value, String message) {
        if (value <= start || value >= end) {
            throw new CommandException(String.format(message));
        }
    }

    public void exclusiveBetween(double start, double end, double value) {
        if (value <= start || value >= end) {
            throw new CommandException(String.format("The value %s is not in the specified exclusive range of %s to %s", value, start, end));
        }
    }

    public void exclusiveBetween(double start, double end, double value, String message) {
        if (value <= start || value >= end) {
            throw new CommandException(String.format(message));
        }
    }

    public void isInstanceOf(Class<?> type, Object obj) {
        if (!type.isInstance(obj)) {
            throw new CommandException(String.format("Expected type: %s, actual: %s", type.getName(), obj == null ? "null" : obj.getClass().getName()));
        }
    }

    public void isInstanceOf(Class<?> type, Object obj, String message, Object... values) {
        if (!type.isInstance(obj)) {
            throw new CommandException(message);
        }
    }

    public void isAssignableFrom(Class<?> superType, Class<?> type) {
        if (!superType.isAssignableFrom(type)) {
            throw new CommandException(String.format("Cannot assign a %s to a %s", type == null ? "null" : type.getName(), superType.getName()));
        }
    }

    public void isAssignableFrom(Class<?> superType, Class<?> type, String message, Object... values) {
        if (!superType.isAssignableFrom(type)) {
            throw new CommandException(message);
        }
    }

}
